<template>
  <view class="OverflowEllipsis">
    <!-- 不可见的  -->
    <!-- #ifndef MP  -->
    <view id="OverflowEllipsis-unitrow" class="unitrow"><br /></view>
    <!-- #endif -->
    <!-- #ifdef MP -->
    <view id="OverflowEllipsis-unitrow" class="unitrow">''</view>
    <!-- #endif -->
    <!-- 隐藏文本长度调整过程 -->
    <view id="OverflowEllipsis-contentBox" class="content-box-copy">
      <text>{{ viewContent }}</text>
      <template v-if="isOverflow && content.length > 0">
        <text v-if="!showAll">...</text>
        <text v-if="showButton" @click="toggleShowAll" class="toggleBtn">
          {{ showAll ? '[折叠]' : '[显示全部]' }}
        </text>
      </template>
    </view>
    <!-- 可见的 -->
    <view v-if="isAdjustFinish" class="content-box">
      <text>{{ viewContent }}</text>
      <template v-if="isOverflow && (content.length > 0)">
        <text v-if="!showAll">...</text>
        <text v-if="showButton" @click="toggleShowAll" class="toggleBtn">
          {{ showAll ? '[折叠]' : '[显示全部]' }}
        </text>
      </template>
    </view>
  </view>
</template>

<script>
export default {
  name: 'OverflowEllipsis',
  props: {
    content: String,
    line: {
      type: Number,
      default: 1
    },
    showButton:{
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      viewContentLength: 0, //控制展示长度
      foldViewContentLength: 0, //记录展示特定行数的文本长度
      showAll: false, //文本展示状态
      isOverflow: true, //文本是否超出指定行数
      isOverFlowHeight: 0,
      isAdjustFinish: false
    };
  },
  watch: {
    content: {
      handler() {
        this.init();
        this.$nextTick(() => {
          this.content && this.adjustContentLength();
        });
      },
      immediate: true
    }
  },
  computed: {
    viewContent() {
      return this.content.slice(0, this.viewContentLength);
    }
  },
  mounted() {
    this.getIsOverFlowHeight();
  },
  methods: {
    init() {
      this.viewContentLength = this.content.length; //初始化长度用于自动长度调整
      this.isOverflow = true;
      this.showAll = false;
      this.isAdjustFinish = false;
    },
    getIsOverFlowHeight() {
      uni
        .createSelectorQuery()
        // #ifndef MP-ALIPAY
        .in(this)
        // #endif
        .select(`#OverflowEllipsis-unitrow`)
        .boundingClientRect()
        .exec(ret => {
          this.isOverFlowHeight = ret[0].height * this.line;
        });
    },
    checkIsOverflow() {
      return new Promise((resolve, reject) => {
        uni
          .createSelectorQuery()
          // #ifndef MP-ALIPAY
          .in(this)
          // #endif
          .select(`#OverflowEllipsis-contentBox`)
          .boundingClientRect()
          .exec(ret => {
            const isOverflow = ret[0].height > this.isOverFlowHeight;
            resolve(isOverflow);
          });
      });
    },
    async adjustContentLength(start = 0, end = this.content.length) {
      if (start + 1 >= end) {
        this.foldViewContentLength = this.viewContentLength;
        this.isOverflow = this.content.length > this.viewContentLength;
        this.isAdjustFinish = true;
        return;
      }
      const isOverflow = await this.checkIsOverflow();
      isOverflow ? (end = this.viewContentLength) : (start = this.viewContentLength);
      this.viewContentLength = Math.floor((start + end) / 2);
      this.$nextTick(() => {
        this.adjustContentLength(start, end);
      });
    },
    toggleShowAll() {
      this.viewContentLength = this.showAll ? this.foldViewContentLength : this.content.length;
      this.showAll = !this.showAll;
    }
  }
};
</script>

<style scoped>
.OverflowEllipsis {
  position: relative;
}

.unitrow {
  visibility: hidden;
  position: absolute;
  padding: 0;
  margin: 0;
}

.toggleBtn {
  white-space: nowrap;
  cursor: pointer;
  font-weight: bold;
}

.content-box-copy {
  visibility: hidden;
  position: absolute;
}
</style>
